/* SekiOS - rtc.c
 *  
 * real-time clock things
 *  
 * credits: Uranium-238, Napalm
 */

#include <master.h>

struct tm global_time;
int rtc_is_bcd;

static unsigned char rtc_read_register(unsigned char reg)
{
    outportb(0x70, reg);
    return inportb(0x71);
}

static void rtc_write_register(unsigned char reg, unsigned char value)
{
    outportb(0x70, reg);
    outportb(0x71, value);
}

static unsigned char bcd2bin(unsigned char bcd)
{
    return ((bcd >> 4) * 10) + (bcd & 0x0F);
}

void gettime(struct tm *time)
{
    memcpy(time, &global_time, sizeof(time_t));
}

void rtc_handler(struct regs* r)
{
    if(rtc_read_register(0x0C) & 0x10){
        if(rtc_is_bcd){
            global_time.tm_sec   = bcd2bin(rtc_read_register(0x00));
            global_time.tm_min   = bcd2bin(rtc_read_register(0x02));
            global_time.tm_hour  = bcd2bin(rtc_read_register(0x04));
            global_time.tm_mon   = bcd2bin(rtc_read_register(0x08));
            global_time.tm_year  = bcd2bin(rtc_read_register(0x09));
            global_time.tm_wday  = bcd2bin(rtc_read_register(0x06));
            global_time.tm_mday  = bcd2bin(rtc_read_register(0x07));
        }else {
            global_time.tm_sec   = rtc_read_register(0x00);
            global_time.tm_min   = rtc_read_register(0x02);
            global_time.tm_hour  = rtc_read_register(0x04);
            global_time.tm_mon   = rtc_read_register(0x08);
            global_time.tm_year  = rtc_read_register(0x09);
            global_time.tm_wday  = rtc_read_register(0x06);
            global_time.tm_mday  = rtc_read_register(0x07);
        }
    }
}

void rtc_install(void)
{
    unsigned char status;
    
    status = rtc_read_register(0x0B);
    status |=  0x02;             // 24 hour clock
    status |=  0x10;             // update ended interrupts
    status &= ~0x20;             // no alarm interrupts
    status &= ~0x40;             // no periodic interrupt
    rtc_is_bcd     =  !(status & 0x04); // check if data type is BCD
    rtc_write_register(0x0B, status);

    rtc_read_register(0x0C);

    irq_install_handler(8, rtc_handler);
}
